﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace MipsPipelineSimulator
{
    public partial class MemoryControl : UserControl
    {
        public RichListView memoryListView = null; 

        public MemoryControl()
        {
            InitializeComponent();
            memoryListView = new RichListView(2,false);
            ColumnHeader name = new ColumnHeader();
            name.Text = "地址";
            name.Width = this.Width/2;
            ColumnHeader value = new ColumnHeader();
            value.Text = "值";
            value.Width = this.Width / 2 - 40;
            memoryListView.Columns.AddRange(new ColumnHeader[2] { name, value });
            this.Controls.Add(memoryListView);

            memoryListView.SetColumnEditable(2, new RichListView.validate(this.validateValue));
            memoryListView.SetColumnEditable(1, new RichListView.validate(this.validateAddress));

            for (long i = 0; i < 64; i++)
            {
                string[] s = new string[2];
                s[0] = CommonTool.NumToStr(TypeCode.Int64, i, "X", true);
                s[1] = "00";
                memoryListView.Items.Add(new ListViewItem(s));
            }
        }

        public RichListView RichListView
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }

        private void MemoryControl_Load(object sender, EventArgs e)
        {
            
        }

        public bool validateValue(string inputStr)
        {
            Regex r = new Regex(@"[0-9A-Fa-f]{2}$");
            return r.Match(inputStr).Success;
        }

        public bool validateAddress(string inputStr)
        {
            Regex r = new Regex(@"[0-9A-Fa-f]{16}$");
            return r.Match(inputStr).Success;
        }

        public void SetMemoryValue(Int64 address,TypeCode type,object value)
        {
            switch (type)
            {
                case TypeCode.Int32:
                    {
                        Dictionary<string,string> dic= new Dictionary<string,string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.Int32, value, "X", true);
                        for (int i = 0; i < 4; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr,valueStr.Substring(i*2,2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.UInt32:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.UInt32, value, "X", true);
                        for (int i = 0; i < 4; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.Int16:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.Int16, value, "X", true);
                        for (int i = 0; i < 2; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.UInt16:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.UInt16, value, "X", true);
                        for (int i = 0; i < 2; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.SByte:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.SByte, value, "X", true);
                        for (int i = 0; i < 1; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.Byte:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.Byte, value, "X", true);
                        for (int i = 0; i < 1; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.Int64:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.Int64, value, "X", true);
                        for (int i = 0; i < 8; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.UInt64:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.UInt64, value, "X", true);
                        for (int i = 0; i < 8; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.Single:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.Single, value, "X", true);
                        for (int i = 0; i < 4; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
                case TypeCode.Double:
                    {
                        Dictionary<string, string> dic = new Dictionary<string, string>();
                        string valueStr = CommonTool.NumToStr(TypeCode.Double, value, "X", true);
                        for (int i = 0; i < 8; i++)
                        {
                            string addrStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
                            dic.Add(addrStr, valueStr.Substring(i * 2, 2));
                            address += 1;
                        }
                        this.SetMemoryValue(dic);
                        break;
                    }
            }
        }

        private void SetMemoryValue(Dictionary<string, string> dic)
        {
            List<KeyValuePair<string, string>> list = dic.ToList();
            foreach (ListViewItem listview in this.memoryListView.Items)
            {
                if (dic.Count == 0) return;
                for(int i=0;i<list.Count;i++)
                {
                    KeyValuePair<string, string> pair = list[i];
                    if (pair.Key == listview.Text)
                    {
                        listview.SubItems[1].Text = pair.Value;
                        list.RemoveAt(i);
                        i--;
                    }
                }
            }
            if (list.Count != 0)
            {
                foreach (KeyValuePair<string, string> pair in list)
                {
                    string[] s = new string[2];
                    s[0] = pair.Key;
                    s[1] = pair.Value;
                    this.memoryListView.Items.Add(new ListViewItem(s));
                }
            }
        }

        public object GetMemoryValue(Int64 address,TypeCode type)
        {
            switch (type)
            {
                case TypeCode.Int32:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 4; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (Int32)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.Int32, resultStr, 16);
                    }
                case TypeCode.UInt32:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 4; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (UInt32)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.UInt32, resultStr, 16);
                    }
                case TypeCode.Int64:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 8; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (Int64)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.Int64, resultStr, 16);
                    }
                case TypeCode.UInt64:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 8; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (UInt64)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.UInt64, resultStr, 16);
                    }
                case TypeCode.Int16:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 2; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (Int16)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.Int16, resultStr, 16);
                    }
                case TypeCode.UInt16:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 2; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (UInt16)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.UInt16, resultStr, 16);
                    }
                case TypeCode.SByte:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 1; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (SByte)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.SByte, resultStr, 16);
                    }
                case TypeCode.Byte:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 1; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (Byte)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.Byte, resultStr, 16);
                    }
                case TypeCode.Single:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 4; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (Single)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.Single, resultStr, 16);
                    }
                case TypeCode.Double:
                    {
                        string resultStr = "";
                        for (int i = 0; i < 8; i++)
                        {
                            string tmp = this.GetGetMemoryValue(address);
                            if (tmp == null)
                            {
                                resultStr = null;
                                return (Double)0;
                            }
                            resultStr += tmp;
                            address++;
                        }
                        return CommonTool.StrToNum(TypeCode.Double, resultStr, 16);
                    }
            }
            return null;
        }

        private string GetGetMemoryValue(Int64 address)
        {
            string addressStr = CommonTool.NumToStr(TypeCode.Int64, address, "X", true);
            ListViewItem memory = this.memoryListView.FindItemWithText(addressStr, false, 0);
            if (memory == null) return null;
            else
            {
                return memory.SubItems[1].Text;
            }
        }
    }
}
